<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ganttExp2-手动改变画布尺寸</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        html,
        body {
            width: 100%;
            height: 100%;
            overflow: auto;
        }

        .gantt-box {
            position: relative;
            padding: 5px;
            /* 添加5px的外扩 */
            box-sizing: border-box;
            /* 确保padding不会增加元素的总宽度和高度 */
            width: 100%;
            height: 100%;
        }

        .cvs1 {
            width: 100%;
            height: 100%;
            border: 1px solid red;
        }

        .zoom-controls {
            position: absolute;
            top: 10px;
            right: 10px;
            padding: 5px;
            border: 1px solid #ccc;
            background-color: rgba(255, 255, 255, 0.5);
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            font-size: 10px;
            z-index: 10;
        }

        .zoom-controls input {
            text-align: center;
        }
    </style>

    <script type="text/javascript" src="https://www.jeasyui.com/easyui/jquery.min.js"></script>
    <script type="text/javascript" src="https://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/luxon@1.27.0/build/global/luxon.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.0.0"></script>
    <script type="module">


        // 初始化 DataGrid
        const initTasks = [
            {
                name: '框柱安装1组', color: 'rgba(255, 99, 132, 0.2)',
                meshs: [
                    { name: '1', timestamp: 1676248341000 },
                    { name: '2', timestamp: 1676255541000 },
                    { name: '3', timestamp: 1676262741000 },
                    { name: '4', timestamp: 1676269941000 },
                    { name: '5', timestamp: 1676277141000 },
                    { name: '6', timestamp: 1676284341000 },
                    { name: "7", timestamp: 1676334741000 },
                    {
                        "name": "8",
                        "timestamp": 1676341941000
                    },
                    {
                        "name": "9",
                        "timestamp": 1676349141000
                    },
                    {
                        "name": "10",
                        "timestamp": 1676356341000
                    },
                    {
                        "name": "11",
                        "timestamp": 1676363541000
                    },
                    {
                        "name": "12",
                        "timestamp": 1676370741000
                    }
                ]
            },
            {
                name: '框柱安装2组', color: 'rgba(54, 162, 235, 0.2)',
                meshs: [
                    { name: '13', timestamp: 1676421141000 },
                    { name: '14', timestamp: 1676431141000 },
                    { name: '15', timestamp: 1676441141000 },
                    { name: '16', timestamp: 1676451141000 },
                    { name: '17', timestamp: 1676461141000 },
                    { name: '18', timestamp: 1676471141000 },
                    { name: '19', timestamp: 1676334741000 },
                    { name: '20', timestamp: 1676344741000 },
                    { name: '21', timestamp: 1676354741000 },
                    { name: '22', timestamp: 1676364741000 },
                    { name: '23', timestamp: 1676374741000 },
                    { name: '24', timestamp: 1676384741000 }
                ]
            },
            {
                name: '框柱安装3组', color: 'rgba(255, 206, 86, 0.2)',
                meshs: [
                    { name: '25', timestamp: 1676593941000 },
                    { name: '26', timestamp: 1676603941000 },
                    { name: '27', timestamp: 1676613941000 },
                    { name: '28', timestamp: 1676623941000 },
                    { name: '29', timestamp: 1676633941000 },
                    { name: '30', timestamp: 1676643941000 },
                    { name: '31', timestamp: 1676513941000 },
                    { name: '32', timestamp: 1676523941000 },
                    { name: '33', timestamp: 1676533941000 },
                    { name: '34', timestamp: 1676543941000 },
                    { name: '35', timestamp: 1676553941000 },
                    { name: '36', timestamp: 1676563941000 }
                ]
            }
        ];

        // console.log('initTasks:', initTasks);
        let initialTasks = initTasks.map(task => {
            return updateTaskDates(task);
        });
        let tasksData = [];

        function updateTaskDates(task) {
            if (!task.meshs || task.meshs.length === 0) {
                task.StartDate = '';
                task.Duration = '';
                return;
            }
            // console.log(task)

            // console.log('taskmeshs2:',luxon.DateTime.fromFormat(task.meshs[0].timestamp, 'dd/MM/yyyy HH:mm:ss'))   
            const dates = task.meshs.map(mesh => mesh.timestamp);
            // console.log('dates:', dates)
            const minDate = luxon.DateTime.fromMillis(
                dates.reduce((min, date) => date < min ? date : min)
            );
            const maxDate = luxon.DateTime.fromMillis(
                dates.reduce((max, date) => date > max ? date : max)
            );

            console.log('minDate:', minDate)
            console.log('maxDate:', maxDate)

            // minDate = luxon.DateTime.fromSeconds(minDate.ts/1000)
            // maxDate = luxon.DateTime.fromSeconds(maxDate.ts/1000)
            // console.log(luxon.DateTime.fromSeconds(minDate.ts/1000).toISODate());
            // console.log(minDate.toISODate());
            task.StartDate = minDate.toISODate();
            task.Duration = maxDate.diff(minDate, 'days').days;
            console.log('task:', task);
            return task;
        }


        $(document).ready(function () {
            //////////////////
            // 初始化甘特图
            //////////////////
            const ctx = document.getElementById('ganttChart').getContext('2d');
            let ganttChart;

            function initGanttChart(tasks) {
                if (ganttChart) {
                    ganttChart.destroy(); // 销毁旧的图表实例
                }
                //console.log(tasks);
                //console.log(getMinDate(tasks));
                ganttChart = new Chart(ctx, {
                    type: 'bar',
                    data: {
                        labels: tasks.map(task => task.name)
                    },
                    options: {
                        indexAxis: 'y',
                        aspectRatio: false,    // 宽度自适应
                        scales: {
                            x: {
                                type: 'time',
                                time: {
                                    unit: 'day',
                                    tooltipFormat: 'yyyy-MM-dd'
                                },
                                min: getMinDate(tasks),
                                max: getMaxDate(tasks)
                            },
                            y: {
                                ticks: {
                                    autoSkip: false
                                }
                            }
                        },
                        plugins: {
                            legend: {
                                display: false
                            },
                            title: {
                                display: true,
                                text: '横道图示例'
                            }
                        },
                        elements: {
                            bar: {
                                display: false
                            }
                        }
                    },
                    plugins: [{
                        id: 'customGantt',
                        afterDraw: function (chart) {
                            console.log(chart);
                            const ctx = chart.ctx;
                            const xScale = chart.scales.x;
                            const yScale = chart.scales.y;

                            tasks.forEach((task, index) => {
                                // console.log('task:',task);
                                const startDate = task.meshs.reduce((min, mesh) => {
                                    const start = luxon.DateTime.fromMillis(mesh.timestamp);
                                    return start < min ? start : min;
                                }, luxon.DateTime.fromMillis(task.meshs[0].timestamp));
                                 console.log('startDate:',startDate);

                                const endDate = startDate.plus({ days: task.Duration });

                                const x = xScale.getPixelForValue(startDate);
                                const y = yScale.getPixelForValue(task.name) - 12;
                                const width = xScale.getPixelForValue(endDate) - x;
                                const height = 24;

                                ctx.fillStyle = task.color;
                                ctx.fillRect(x, y, width, height);

                                ctx.fillStyle = '#000';
                                ctx.font = '12px Arial';
                                ctx.textAlign = 'center';
                                ctx.fillText(task.name, x + width / 2, y + height / 2 + 4);
                            });
                        }
                    }]
                });
            }

            // 获取任务的最小开始时间
            function getMinDate(tasks) {
                return tasks.reduce((min, task) => {
                    const start = luxon.DateTime.fromISO(task.StartDate).minus({ days: 1 });
                    return start < min ? start : min;
                }, luxon.DateTime.fromISO(tasks[0].StartDate).minus({ days: 1 })).toISODate();
            }

            // 获取任务的最大结束时间
            function getMaxDate(tasks) {
                //console.log(luxon.DateTime.fromISO(tasks[0].StartDate).toISODate());
                return tasks.reduce((max, task) => {
                    const end = luxon.DateTime.fromISO(task.StartDate).plus({ days: task.Duration + 2 });
                    return end > max ? end : max;
                }, luxon.DateTime.fromISO(tasks[0].StartDate).plus({ days: tasks[0].Duration + 2 })).toISODate();
            }

            // 初始化甘特图
            initGanttChart(initialTasks);

            ///////////////////////////////////////////////////////////////////////////

            //////////////////////////
            // 添加画布缩放功能
            /////////////////////////
            // 新增缩放控制逻辑
            const widthZoomInput = $('#widthZoomInput');
            const heightZoomInput = $('#heightZoomInput');
            

            function updateCanvasSize() {
                const widthPercent = Math.min(
                    Math.max(
                        parseInt(
                            widthZoomInput.val().replace('%', '')
                        ) || 100, 10
                    ),
                    200
                );
                const heightPercent = Math.min(
                    Math.max(
                        parseInt(
                            heightZoomInput.val().replace('%', '')
                        ) || 100, 10
                    ),
                    200
                );

                widthZoomInput.val(`${widthPercent}%`);
                heightZoomInput.val(`${heightPercent}%`);

                $('#ganttBox').css({
                    width: `${widthPercent}%`,
                    height: `${heightPercent}%`
                });

                // 初始化甘特图
                // initGanttChart(initialTasks);
            }

            // 绑定按钮事件
            $('#widthZoomIn, #heightZoomIn').on('click', function (e) {
                console.log('e.target.id:', e.target.id);
                const isWidth = e.target.id === 'widthZoomIn';
                const input = isWidth ? widthZoomInput : heightZoomInput;
                const value = Math.min(parseInt(input.val().replace('%', '')) + 10, 200);
                input.val(`${value}%`);
                updateCanvasSize();
            });

            $('#widthZoomOut, #heightZoomOut').on('click', function (e) {
                console.log('e.target.id:', e.target.id);
                const isWidth = e.target.id === 'widthZoomOut';
                const input = isWidth ? widthZoomInput : heightZoomInput;
                const value = Math.max(parseInt(input.val().replace('%', '')) - 10, 10);
                input.val(`${value}%`);
                updateCanvasSize();
            });

            // 绑定输入框事件
            widthZoomInput.add(heightZoomInput).on('change', function () {
                this.value = this.value.replace(/[^0-9%]/g, '');
                if (!this.value.endsWith('%')) this.value += '%';
                updateCanvasSize();
            });

        });
    </script>
</head>

<body>
    <div class="gantt-box" id="ganttBox">
        <canvas id="ganttChart" class="cvs1"></canvas>

    </div>
    <!-- 添加画布缩放控件 -->
    <div class="zoom-controls" id="zoomControls">
        <span>宽度缩放：</span><button id="widthZoomIn">+</button>
        <input type="text" size="5" id="widthZoomInput" value="100%" />&nbsp;<button
            id="widthZoomOut">-</button><br><br>
        <span>高度缩放：</span><button id="heightZoomIn">+</button>
        <input type="text" size="5" id="heightZoomInput" value="100%" />&nbsp;<button id="heightZoomOut">-</button>
    </div>
</body>

</html>